package org.atlantis.datasink.cfg;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.atlantis.datasink.codec.CodecOption;
import org.atlantis.datasink.codec.ICodec;
import org.atlantis.datasink.server.IServer;
import org.atlantis.datasink.server.ServerOption;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

// TODO 如果xsd文件不能完成name重复判断的功能，这里需要进行检查
public class OptionIniter {

	private static final Logger log = LoggerFactory.getLogger(OptionIniter.class);

	public static final String XML_CFG_FILE = "datasink.xml";

	public static final String SERVERS_TAG = "servers";
	public static final String SERVER_TAG = "server";
	public static final String CODECS_TAG = "codecs";
	public static final String CODEC_TAG = "codec";
	public static final String QUEUES_TAG = "queues";
	public static final String QUEUE_TAG = "queue";

	private Map<String, CodecOption> codecOpts = new HashMap<String, CodecOption>();
	private Map<String, ServerOption> serverOpts = new HashMap<String, ServerOption>();

	private CodecOptionFragment codecFrag = new CodecOptionFragment();
	private ServerOptionFragment serverFrag = new ServerOptionFragment();
	private QueueOptionFragment queueFrag = new QueueOptionFragment();

	public void readCfg() throws Exception {
		log.info("Read configuration file: " + XML_CFG_FILE);
		readXml();
		log.info("Read configuration file finish");
	}

	private void readXml() throws Exception {
		File xmlFile = new File(OptionIniter.class.getClassLoader().getResource(XML_CFG_FILE).toURI());
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document doc = builder.parse(xmlFile);
		Element root = (Element) doc.getElementsByTagName("datasink").item(0);

		parseServers(parseNodes(SERVERS_TAG, SERVER_TAG, root));
		parseCodecs(parseNodes(CODECS_TAG, CODEC_TAG, root));
		parseQueues(parseNodes(QUEUES_TAG, QUEUE_TAG, root));
	}

	private NodeList parseNodes(String groupTag, String itemTag, Element root) {
		NodeList group = root.getElementsByTagName(groupTag);
		Node groupNode = group.item(0);
		NodeList items = ((Element) groupNode).getElementsByTagName(itemTag);
		return items;
	}

	private void parseServers(NodeList servers) throws Exception {
		for (int i = 0; i < servers.getLength(); i++) {
			Node server = servers.item(i);
			ServerOption servOpt = serverFrag.parse((Element) server);
			serverOpts.put(servOpt.getName(), servOpt);
		}
		log.info("Read server options complete");
	}

	private void parseCodecs(NodeList codecs) throws Exception {
		for (int i = 0; i < codecs.getLength(); i++) {
			Node codec = codecs.item(i);
			CodecOption codecOpt = codecFrag.parse((Element) codec);
			codecOpts.put(codecOpt.getName(), codecOpt);
		}
		log.info("Read codec options complete");
	}

	private void parseQueues(NodeList queues) throws Exception {
		for (int i = 0; i < queues.getLength(); i++) {
			Node queue = queues.item(i);
			queueFrag.parse((Element) queue);
		}
		log.info("Read queue options complete");
	}

	public ServerOption bindServerOption(IServer server) {
		ServerOption option = serverOpts.get(server.getName());
		if (option == null) return null;
		server.bindOption(option);
		return option;
	}

	public CodecOption bindCodecOption(ICodec codec) {
		CodecOption option = codecOpts.get(codec.getName());
		if (option == null) return null;
		codec.bindOption(option);
		return option;
	}
}
